#ifndef _CLIPROTOHEADER_H_
#define _CLIPROTOHEADER_H_

#include "commonheader.h"
#include <string.h>
#include "type.h"

// mark flag
#define  MARK   0xAABB


#pragma pack(push,1)
struct SCliProHead {
	uint16  wMark;         // mark
	uint16  wCheckSum;     // checksum
	uint16  wDataLen;      // data len
	uint16  wDummy;        // dummy data.
};
#pragma pack(pop)

#define BuildPacketHead(stHead, wLen) do {                    \
	(stHead).wDataLen    = htons(wLen);                       \
    (stHead).wMark       = htons(MARK);                       \
    (stHead).wCheckSum   = htons(((wLen) ^ 0xAABB) & 0x88AA); \
} while (0)

// global client protocol head size.
static uint32 g_wClientProHeadSize = sizeof(SCliProHead);

// build packet head
inline uint32 BuildPacket(char* pPacket, uint32 dwPackSize, const char* pData, uint16 wLen) {
	if (dwPackSize < g_wClientProHeadSize + wLen) {
		return 0;
	}

	SCliProHead* pstHead = (SCliProHead*)pPacket;
	BuildPacketHead(*pstHead, wLen);
	memcpy(pPacket + g_wClientProHeadSize, pData, wLen);
	return g_wClientProHeadSize + wLen;
}

// check a complete packet, including packet head
// complete packet return real len
// invalid packet return -1, not a complete packet return 0
#define CheckPacketRet(pData, wLen)   {                           \
	if (wLen < g_wClientProHeadSize) {                            \
		return 0;                                                 \
	}                                                             \
                                                                  \
	const SCliProHead* pstCliHead = (const SCliProHead*)pData;    \
	uint16 wDataLen      = ntohs(pstCliHead->wDataLen);           \
	uint16 wMark         = ntohs(pstCliHead->wMark);              \
	uint16 wCheckSum     = ntohs(pstCliHead->wCheckSum);          \
	uint16 wCalcCheckSum = (wDataLen ^ 0xAABB) & 0x88AA;          \
	                                                              \
	if (wCheckSum != wCalcCheckSum || wMark != MARK) {            \
		return -1;                                                \
	}                                                             \
	                                                              \
	if (wLen >= wDataLen + g_wClientProHeadSize) {                \
		return wDataLen + g_wClientProHeadSize;                   \
	}                                                             \
	                                                              \
	return 0;                                                     \
}


inline int CheckPacket(const char* pData, uint16 wLen) {
	if (wLen < g_wClientProHeadSize) {
		return 0;
	}

	const SCliProHead* pstCliHead = (const SCliProHead*)pData;
	uint16 wDataLen = ntohs(pstCliHead->wDataLen);
	uint16 wMark = ntohs(pstCliHead->wMark);
	uint16 wCheckSum = ntohs(pstCliHead->wCheckSum);
	uint16 wCalcCheckSum = (wDataLen ^ 0xAABB) & 0x88AA;

	if (wCheckSum != wCalcCheckSum || wMark != MARK) {
		return -1;
	}

	if (wLen >= wDataLen + g_wClientProHeadSize) {
		return wDataLen + g_wClientProHeadSize;
	}

	return 0;
}

#endif
